home *** CD-ROM | disk | FTP | other *** search
/ ShareWare OnLine 2 / ShareWare OnLine Volume 2 (CMS Software)(1993).iso / os2 / monte.zip / IPC / IPC.C next >
Text File  |  1993-03-05  |  5KB  |  166 lines

  1. /* ipc.c
  2.  
  3. This sample shows the use of a mutual exclusion semaphore to protect multiple
  4. thread access to a resource.  The resource here is the printf() function.
  5. printf does not need semaphore protection when using multithread C libraries,
  6. but nevermind that for the sake of example.
  7.  
  8. All created threads block on the request of the mutex sem until thread 1
  9. releases it.
  10.  
  11. Note that the threads obtain the mutex sem in the order they requested it.
  12.  
  13. The threads are created by thread 1, then thread 1 waits on a compound
  14. (muxwait, wait-all) semaphore which contains one semaphore for each thread
  15. started.  When each thread is about to exit, it posts its respective
  16. semaphore.  When all the semaphores in the muxwait semaphore are posted,
  17. thread 1 wakes up and terminates the process.
  18.  
  19. An exercise would be to raise the priority of a given thread to see if that
  20. thread is the first to obtain the mutex sem when thread 1 releases it.
  21.  
  22. */
  23.  
  24. #define INCL_DOS
  25. #include <os2.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <assert.h>
  30.  
  31. #define SEMNAME_ACK       "\\SEM32\\ACK"
  32. #define SEMNAME_SERIAL    "\\SEM32\\SERIAL"
  33. #define SEMNAME_MUX       "\\SEM32\\MUX"
  34. #define COLORNAMES        "amber blue cyan green mauve teal"
  35.  
  36. struct _threadparms {
  37.   PSZ     pszColorname;
  38.   HEV     hev;
  39. };
  40. typedef struct _threadparms THREADPARMS, *PTHREADPARMS;
  41.  
  42. // global variables
  43. HEV      hevAck;
  44. HMTX     hmtxSerial;
  45.  
  46.  
  47.  
  48.  
  49. // ----------------------------------------------------------------------
  50. void _Optlink threadcode( void* pv )
  51. {
  52.   APIRET      rc;
  53.   char        szColor[ 32 ];
  54.   HEV         hev;
  55.  
  56.   // copy parameters to local storage; the post the acknowledge semaphore
  57.   strcpy( szColor, ((PTHREADPARMS)pv)->pszColorname );
  58.   hev = ((PTHREADPARMS)pv)->hev;
  59.   rc = DosPostEventSem( hevAck );
  60.   assert( rc == 0 );
  61.  
  62.   // this request will block until thread 1 does a release
  63.   rc = DosRequestMutexSem( hmtxSerial, -1 );
  64.   assert( rc == 0 );
  65.  
  66.   printf( "%s\n", szColor );
  67.  
  68.   rc = DosReleaseMutexSem( hmtxSerial );
  69.   assert( rc == 0 );
  70.   rc = DosPostEventSem( hev );
  71.   assert( rc == 0 );
  72.  
  73.   // return to the C runtime for thread exiting
  74.   return;
  75. }
  76.  
  77.  
  78.  
  79. //-------------------------------------------------------------------------
  80. int main( void )
  81. {
  82.   int          i;
  83.   char         *pch,  szWork[ 100 ];
  84.   APIRET       rc;
  85.   HEV          hev;
  86.   HMUX         hmux;
  87.   SEMRECORD    aSemrecord[ 32 ];
  88.   ULONG        ulThreadCount, ulPostCount, ulUser;
  89.   THREADPARMS  threadparms;
  90.   TID          tid;
  91.  
  92.  
  93.   // handles to sems are stored in global static variables accessible from both threads
  94.  
  95.   // sem used by thread 2 to ack thread 1
  96.   rc = DosCreateEventSem( SEMNAME_ACK, &hevAck, 0, TRUE );
  97.   assert( rc == 0 );
  98.  
  99.   // mutual-exclusion semaphore to serialize access to a serially-reusable resource
  100.   // create "set" so all other thread block on it until released
  101.   rc = DosCreateMutexSem( SEMNAME_SERIAL, &hmtxSerial, 0, TRUE );
  102.   assert( rc == 0 );
  103.  
  104.   // count the number of threads created; same as number of colors in COLORNAMES string
  105.   ulThreadCount = 0;
  106.  
  107.   // use strtok to parse the colors from the COLORNAMES string
  108.   pch = strtok( COLORNAMES, " " );
  109.   while( pch ) {
  110.  
  111.     // reset this event semaphore; created thread will post it as an acknowledgement
  112.     rc = DosResetEventSem(  hevAck, &ulPostCount );
  113.     assert( rc == 0 );
  114.  
  115.     // name and create an event semaphore using color name
  116.     sprintf( szWork, "\\SEM32\\%s", pch );
  117.     rc = DosCreateEventSem( szWork, &hev, 0, FALSE );
  118.     assert( rc == 0 );
  119.  
  120.     // prepare this element of the SEMRECORD array; required below for compound sem wait
  121.     aSemrecord[ ulThreadCount ].hsemCur   = (HSEM)hev;
  122.     aSemrecord[ ulThreadCount ].ulUser    = ulThreadCount;
  123.  
  124.     // argument to thread is a pointer to a structure of arguments
  125.     threadparms.pszColorname   = pch;
  126.     threadparms.hev            = hev;
  127.  
  128.     // use beginthread to ensure C runtime support is properly initialized
  129.     i = _beginthread( threadcode, NULL, 2*4096, (void *)&threadparms );
  130.     assert( i );
  131.  
  132.     ulThreadCount++;
  133.  
  134.     // wait on acknowledgement from thread; params copied
  135.     rc = DosWaitEventSem( hevAck, 5000 );
  136.     assert( rc == 0 );
  137.     pch = strtok( NULL, " " );
  138.   }
  139.  
  140.   // create the compound (mux) semaphore;
  141.   // a wait on this sem will wait until all sem in the array post
  142.   rc = DosCreateMuxWaitSem( SEMNAME_MUX, &hmux, ulThreadCount, aSemrecord, DCMW_WAIT_ALL );
  143.   assert( rc == 0 );
  144.  
  145.   // release this semaphore and some thread with soon obtain it via DosRequestMutexSem
  146.   rc = DosReleaseMutexSem( hmtxSerial );
  147.   assert( rc == 0 );
  148.  
  149.   // this wait ends when all threads have requested, then released the mutex sem
  150.   rc = DosWaitMuxWaitSem( hmux, -1, &ulUser );
  151.   assert( rc == 0 );
  152.  
  153.   // ensure threads are gone
  154.   while( ulThreadCount ) {
  155.     // add one because I created threads 2...n
  156.     tid = ulThreadCount+1;
  157.     rc = DosWaitThread( &tid, DCWW_WAIT );
  158.     // rc 309 is invalid thread id, meaning thread has already exited
  159.     assert( 309 == rc || 0 == rc );
  160.     ulThreadCount--;
  161.   }
  162.  
  163.   // threads are gone; return to the C runtime for exiting thread 1
  164.   return 0;
  165. }
  166.